#pragma once

#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#else
#include <pthread.h>
#endif


namespace base {

namespace eec {

class mutex {
public:
    mutex() {
#ifdef WIN32
        InitializeCriticalSection(&vl_);
#else
        pthread_mutex_init(&vl_, NULL);
#endif
    }
    ~mutex() {
#ifdef WIN32
        DeleteCriticalSection(&vl_);
#else
        pthread_mutex_destroy(&vl_);
#endif
    }

public:
    void lock() {
#ifdef WIN32
        EnterCriticalSection(&vl_);
#else
        pthread_mutex_lock(&vl_);
#endif
    }
    void unlock() {
#ifdef WIN32
        LeaveCriticalSection(&vl_);
#else
        pthread_mutex_unlock(&vl_);
#endif
    }
    bool try_lock() {
#ifdef WIN32
        return (TRUE == TryEnterCriticalSection(&vl_));
#else
        return (0 == pthread_mutex_trylock(&vl_));
#endif
    }

private:
    mutex(const mutex&);
    mutex& operator=(const mutex&);

private:
#ifdef WIN32
    CRITICAL_SECTION vl_;
#else
    pthread_mutex_t vl_;
#endif
};

template<class _Mutex>
class lock_guard {
public:
    lock_guard(_Mutex& _mutex)
        : mutex_(_mutex) {
        mutex_.lock();
    }
    ~lock_guard() {
        mutex_.unlock();
    }

private:
    lock_guard(const lock_guard&);
    lock_guard& operator=(const lock_guard&);
private:
    _Mutex& mutex_;
};

template<class _Mutex>
class unique_lock {

public:
    unique_lock(_Mutex& _mutex)
        : mutex_(_mutex) {
    }
    ~unique_lock() {
        unlock();
    }

public:
    void lock() {
        if (locked_) {
            return;
        }
        mutex_.lock();
        locked_ = true;
    }
    void unlock() {
        if (!locked_) {
            return;
        }
        mutex_.unlock();
        locked_ = false;
    }
    bool try_lock() {
        if (locked_) {
            return;
        }
        if (mutex_.try_lock()) {
            locked_ = true;
        }
        return locked_;
    }

private:
    unique_lock(const unique_lock&);
    unique_lock& operator=(const unique_lock&);

private:
    bool locked_;
    _Mutex& mutex_;
};

}   // namespace eec

}   // namespace base
